<template>
  <view class="chatInterface" @contextmenu.prevent="">
    <image class="group-icon" src="/static/images/group-icon.png" @click="showMembers"/>
    <view class="scroll-view">
      <image v-if="history.loading" class="history-loaded" src="/static/images/loading.svg"/>
      <view v-else :class="history.allLoaded ? 'history-loaded':'load'" @click="loadHistoryMessage(false)">
        <view>{{ history.allLoaded ? '已经没有更多的历史消息' : '点击获取历史消息' }}</view>
      </view>

      <checkbox-group @change="selectMessages">
        <view v-for="(message,index) in history.messages" :key="message.messageId">
          <!--时间显示，类似于微信，隔5分钟不发言，才显示时间-->
          <view class="time-lag">
            {{ renderMessageDate(message, index) }}
          </view>
          <view class="message-recalled" v-if="message.recalled">
            <view v-if="message.recaller.id === currentUser.id" class="message-recalled-self">
              <view>你撤回了一条消息</view>
              <span v-if="message.type === 'text' && Date.now()-message.timestamp< 60 * 1000 "
                    @click="editRecalledMessage(message.payload.text)">重新编辑</span>
            </view>
			      <view v-else>{{ message.recaller.data.name }}撤回了一条消息</view>
          </view>
          <view class="message-item" v-else>
            <view class="message-item-checkbox">
              <checkbox v-show="messageSelector.visible && message.status !== 'sending'" :value="message.messageId"
                        :checked="messageSelector.messages.includes(message)"/>
            </view>
            <view class="message-item-content" :class="{'self' : message.senderId ===  currentUser.id}">
              <view class="avatar">
                <image :src="message.senderData.avatar"></image>
              </view>

              <view class="content" @click.right="showActionPopup(message)" @longpress="showActionPopup(message)">
                <view class="message-payload">
                  <b class="pending" v-if="message.status === 'sending'"></b>
                  <b class="send-fail" v-if="message.status === 'fail'"></b>
                  <view v-if="message.type === 'text'" class="text-content" v-html="renderTextMessage(message)"></view>
                  <image v-if="message.type === 'image'"
                     :data-url="message.payload.url"
                     :src="message.payload.thumbnail"
                     class="image-content"
                     mode="heightFix"
                     @click="showImageFullScreen"
                  ></image>
                  <view class="video-snapshot" v-if="message.type === 'video'" :data-url="message.payload.video.url"
                        @click="playVideo">
                    <image
                      :src="message.payload.thumbnail.url"
                      :style="{height: getImageHeight(message.payload.thumbnail.width,message.payload.thumbnail.height)+'rpx' }"
                      mode="heightFix"
                    ></image>
                    <view class="video-play-icon"></view>
                  </view>
                  <view class="file-content" v-if="message.type === 'file'">
                    <view class="file-info">
                      <span class="file-name">{{ message.payload.name }}</span>
                      <span class="file-size">{{ (message.payload.size / 1024).toFixed(2) }}KB</span>
                    </view>
                    <image class="file-img" src="/static/images/file-icon.png"></image>
                  </view>
                  <view v-if="message.type ==='audio'" class="audio-content" @click="playAudio(message)">
                    <view class="audio-facade" :style="{width:Math.ceil(message.payload.duration)*7 + 50 + 'px'}">
                      <view
                        class="audio-facade-bg"
                        :class="{'play-icon':audioPlayer.playingMessage && audioPlayer.playingMessage.messageId === message.messageId}"
                      ></view>
                      <view>{{Math.ceil(message.payload.duration) || 1}}<span>"</span></view>
                    </view>
                  </view>
                  <view v-if="message.type === 'order'" class="order-content">
                    <view class="order-id">订单号：{{ message.payload.id }}</view>
                    <view class="order-body">
                      <image :src="message.payload.url" class="order-img"></image>
                      <view>
                        <view class="order-name">{{ message.payload.name }}</view>
                        <view class="order-info">
                          <view class="order-price">{{ message.payload.price }}</view>
                          <view class="order-count">共{{ message.payload.count }}件</view>
                        </view>
                      </view>
                    </view>
                  </view>
                </view>
              </view>
            </view>
          </view>
        </view>
      </checkbox-group>
    </view>
    <view class="action-box" v-if="!videoPlayer.visible && !messageSelector.visible">
      <view class="action-top">
        <view @click="switchAudioKeyboard">
          <image class="more" v-if="audio.visible" src="/static/images/jianpan.png"></image>
          <image class="more" v-else src="/static/images/audio.png"></image>
        </view>
        <view v-if="audio.visible" class="record-input" @touchend.stop="onRecordEnd" @touchstart.stop="onRecordStart">
          {{ recorderManager.recording ? '松开发送' : '按住录音' }}
        </view>
        <!-- GoEasyIM最大支持3k的文本消息，如需发送长文本，需调整输入框maxlength值 -->
        <input v-else v-model="text" @confirm="sendTextMessage" class="consult-input" maxlength="700" placeholder="发送消息" type="text" />
        <view @click="switchEmojiKeyboard">
          <image class="more" v-if="emoji.visible" src="/static/images/jianpan.png"></image>
          <image class="more" v-else src="/static/images/emoji.png"></image>
        </view>
        <view>
          <image @click="showOtherTypesMessagePanel()" class="more" src="/static/images/more.png"/>
        </view>
        <view v-if="text" class="send-btn-box">
          <text class="btn" @click="sendTextMessage()">发送</text>
        </view>
      </view>
      <view class="action-bottom action-bottom-emoji" v-if="emoji.visible">
        <image class="emoji-item" v-for="(emojiItem, key, index) in emoji.map" :key="index" :src="emoji.url + emojiItem"
               @click="chooseEmoji(key)"></image>
      </view>
      <!--其他类型消息面板-->
      <view v-if="otherTypesMessagePanelVisible" class="action-bottom">
        <view class="more-icon">
          <image @click="sendImageMessage()" class="operation-icon" src="/static/images/picture.png"></image>
          <view class="operation-title">图片</view>
        </view>
        <view class="more-icon">
          <image @click="sendVideoMessage()" class="operation-icon" src="/static/images/video.png"></image>
          <view class="operation-title">视频</view>
        </view>
        <view class="more-icon">
          <image @click="showOrderMessageList()" class="operation-icon" src="/static/images/order.png"></image>
          <view class="operation-title">订单</view>
        </view>
        <view class="more-icon">
          <image @click="groupCall()" class="operation-icon" src="/static/images/video.png"></image>
          <view class="operation-title">视频通话</view>
        </view>
      </view>
    </view>
    <view class="action-popup" @touchmove.stop.prevent v-if="actionPopup.visible">
      <view class="layer"></view>
      <view class="action-list">
        <view class="action-item" @click="deleteSingleMessage">删除</view>
        <view class="action-item" v-if="actionPopup.recallable" @click="recallMessage">撤回</view>
        <view class="action-item" @click="showCheckBox">多选</view>
        <view class="action-item" @click="hideActionPopup">取消</view>
      </view>
    </view>
    <view class="messageSelector-box" v-if="messageSelector.visible">
      <image class="messageSelector-btn" @click="deleteMultipleMessages" src="/static/images/delete.png"></image>
    </view>
    <view class="record-loading" v-if="recorderManager.recording"></view>
    <video v-if="videoPlayer.visible" :src="videoPlayer.url" id="videoPlayer"
           @fullscreenchange="onVideoFullScreenChange"></video>
    <view v-if="orderList.visible" class="order-list">
      <view class="orders-content">
        <view class="title">
          <view>请选择一个订单</view>
          <view class="close" @click="hideOrderMessageList">×</view>
        </view>
        <view class="orders">
          <view
            v-for="(order, index) in orderList.orders"
            :key="index" class="order-item"
            @click="sendOrderMessage(order)"
          >
            <view class="order-id">订单号：{{ order.id }}</view>
            <view class="order-body">
              <image :src="order.url" class="order-img"></image>
              <view class="order-name">{{ order.name }}</view>
              <view class="order-right">
                <view class="order-price">{{ order.price }}</view>
                <view class="order-count">共{{ order.count }}件</view>
              </view>
            </view>
          </view>
        </view>
      </view>
    </view>
  </view>
</template>

<script>
  import EmojiDecoder from '@/lib/EmojiDecoder';
  import restApi from '@/lib/restapi';
  import {formatDate} from '@/lib/utils';
  import RecorderManager from '@/lib/RecorderManager';

  const IMAGE_MAX_WIDTH = 200;
  const IMAGE_MAX_HEIGHT = 150;
  const recorderManager = new RecorderManager();
  const GoEasy = uni.$GoEasy;
  export default {
    name: 'groupChat',
    data() {
      // 定义表情
      const emojiUrl = 'https://imgcache.qq.com/open/qcloud/tim/assets/emoji/';
      const emojiMap = {
        '[么么哒]': 'emoji_3@2x.png',
        '[乒乓]': 'emoji_4@2x.png',
        '[便便]': 'emoji_5@2x.png',
        '[信封]': 'emoji_6@2x.png',
        '[偷笑]': 'emoji_7@2x.png',
        '[傲慢]': 'emoji_8@2x.png'
      };
      return {
        //聊天文本框
        text: '',
        group: null,
        to: {},// 作为createMessage的参数
        currentUser: null,

        //定义表情列表
        emoji: {
          url: emojiUrl,
          map: emojiMap,
          visible: false,
          decoder: new EmojiDecoder(emojiUrl, emojiMap),
        },
        //是否展示‘其他消息类型面板’
        otherTypesMessagePanelVisible: false,
        orderList: {
          orders: [],
          visible: false
        },
        history: {
          messages: [],
          allLoaded: false,
          loading: false
        },
        recorderManager: recorderManager,
        audio: {
          //录音按钮展示
          visible: false
        },
        audioPlayer: {
          innerAudioContext: null,
          playingMessage: null,
        },
        videoPlayer: {
          visible: false,
          url: '',
          context: null
        },
        // 展示消息删除弹出框
        actionPopup: {
          visible: false,
          message: null,
          recallable: false,
        },
        // 消息选择
        messageSelector: {
          visible: false,
          messages: []
        }
      }
    },
    onLoad(options) {
      //聊天对象
      let id = options.to;
      this.group = restApi.findGroupById(id);
      this.currentUser = uni.$currentUser;
      this.groupMembers = restApi.findGroupMembers(this.group.id);
      this.to = {
        id: this.group.id,
        type: GoEasy.IM_SCENE.GROUP,
        data: {
          name: this.group.name,
          avatar: this.group.avatar
        }
      };

      this.initGoEasyListeners();
      // 语音播放器
      this.initialAudioPlayer();
      // 录音监听器
      this.initRecorderListeners();

    },
    onShow() {
      this.otherTypesMessagePanelVisible = false;
      this.emoji.visible = false;
    },
    onReady() {
      this.loadHistoryMessage(true);
      this.videoPlayer.context = uni.createVideoContext('videoPlayer', this);
      uni.setNavigationBarTitle({
        title: this.group.name + '（' + Object.keys(this.groupMembers).length + '）'
      });
    },
    onPullDownRefresh(e) {
      this.loadHistoryMessage(false);
    },
    onUnload() {
      //退出聊天页面之前，清空监听器
      GoEasy.im.off(GoEasy.IM_EVENT.GROUP_MESSAGE_RECEIVED, this.onMessageReceived);
      GoEasy.im.off(GoEasy.IM_EVENT.MESSAGE_DELETED, this.onMessageDeleted);
    },
    methods: {
      //渲染文本消息，如果包含表情，替换为图片
      //todo:本不需要该方法，可以在标签里完成，但小程序有兼容性问题，被迫这样实现
      renderTextMessage(message) {
        return '<span>' + this.emoji.decoder.decode(message.payload.text) + '</span>';
      },
      //像微信那样显示时间，如果有几分钟没发消息了，才显示时间
      //todo:本不需要该方法，可以在标签里完成，但小程序有兼容性问题，被迫这样实现
      renderMessageDate(message, index) {
        if (index === 0) {
          return formatDate(message.timestamp)
        } else {
          if (message.timestamp - this.history.messages[index - 1].timestamp > 5 * 60 * 1000) {
            return formatDate(message.timestamp)
          }
        }
        return '';
      },
      initGoEasyListeners() {
        // 监听群聊消息
        GoEasy.im.on(GoEasy.IM_EVENT.GROUP_MESSAGE_RECEIVED, this.onMessageReceived);
        //监听消息删除
        GoEasy.im.on(GoEasy.IM_EVENT.MESSAGE_DELETED, this.onMessageDeleted);
      },
      onMessageReceived (message) {
        let groupId = message.groupId;
        if (groupId === this.group.id) {
          this.history.messages.push(message);
          //聊天时，收到消息标记为已读
          this.markGroupMessageAsRead();
          //收到新消息，是滚动到最底部
          this.scrollToBottom();
        }
      },
      onMessageDeleted (deletedMessages) {
        deletedMessages.forEach(message => {
          let groupId = message.groupId;
          if (groupId && groupId === this.group.id) {
            let index = this.history.messages.indexOf(message);
            if (index > -1) {
              this.history.messages.splice(index, 1);
            }
          }
        });
      },
      initialAudioPlayer () {
        this.audioPlayer.innerAudioContext = uni.createInnerAudioContext();
        this.audioPlayer.innerAudioContext.onEnded(() => {
          this.audioPlayer.playingMessage = null;
        });
        this.audioPlayer.innerAudioContext.onStop(() => {
          this.audioPlayer.playingMessage = null;
        });
      },
      initRecorderListeners() {
        recorderManager.onRecordComplete((file, duration) => {
          if (duration < 1000) {
            uni.showToast({
              icon: 'none',
              title: '录音时间太短',
              duration: 500
            });
            return;
          }
          GoEasy.im.createAudioMessage({
            to: this.to,
            file: file,
            notification: {
              title: this.currentUser.name + '发来一段语音',
              body: '[语音消息]',		// 字段最长 50 字符
              sound: 'message',
              badge: '+1'
            },
            onProgress: function (progress) {
              console.log(progress)
            },
            onSuccess: (message) => {
              this.sendMessage(message);
            },
            onFailed: (e) => {
              console.log('error :', e);
            }
          });
        });
      },
      /**
       * 核心就是设置高度，产生明确占位
       *
       * 小  (宽度和高度都小于预设尺寸)
       *    设高=原始高度
       * 宽 (宽度>高度)
       *    高度= 根据宽度等比缩放
       * 窄  (宽度<高度)或方(宽度=高度)
       *    设高=MAX height
       *
       * @param width,height
       * @returns number
       */
      getImageHeight(width, height) {
        if (width < IMAGE_MAX_WIDTH && height < IMAGE_MAX_HEIGHT) {
          return height * 2;
        } else if (width > height) {
          return (IMAGE_MAX_WIDTH / width * height) * 2;
        } else if (width === height || width < height) {
          return IMAGE_MAX_HEIGHT * 2;
        }
      },
      sendMessage(message) {
        this.history.messages.push(message);
        this.scrollToBottom();
        GoEasy.im.sendMessage({
          message: message,
          onSuccess: function (message) {
            console.log('发送成功.', message);
          },
          onFailed: function (error) {
            if (error.code === 507) {
              console.log('发送语音/图片/视频/文件失败，没有配置OSS存储，详情参考：https://docs.goeasy.io/2.x/im/message/media/alioss');
            } else {
              console.log('发送失败:', error);
            }
          }
        });
      },
      sendTextMessage() {
        if (this.text.trim() !== '') {
          let body = this.text;
          if (this.text.length >= 50) {
            body = this.text.substring(0, 30) + '...';
          }
          GoEasy.im.createTextMessage({
            text: this.text,
            to: this.to,
            notification: {
              title: this.currentUser.name + '发来一段文字',
              body: body,
              sound: 'message',
              badge: '+1'
            },
            onSuccess: (message) => {
              this.sendMessage(message);
            },
            onFailed: (e) => {
              console.log('error :', e);
            }
          });
        }
        this.text = '';
      },
      sendVideoMessage() {
        uni.chooseVideo({
          success: (res) => {
            GoEasy.im.createVideoMessage({
              to: this.to,
              file: res,
              notification: {
                title: this.currentUser.name + '发来一个视频',
                body: '[视频消息]',		// 字段最长 50 字符
                sound: 'message',
                badge: '+1'
              },
              onProgress: function (progress) {
                console.log(progress)
              },
              onSuccess: (message) => {
                this.otherTypesMessagePanelVisible = false;
                this.sendMessage(message);
              },
              onFailed: (e) => {
                console.log('error :', e);
              }
            });
          }
        })
      },
      sendImageMessage() {
        uni.chooseImage({
          count: 9,
          success: (res) => {
            res.tempFiles.forEach(file => {
              GoEasy.im.createImageMessage({
                to: this.to,
                file: file,
                notification: {
                  title: this.currentUser.name + '发来一张图片',
                  body: '[图片消息]',		// 字段最长 50 字符
                  sound: 'message',
                  badge: '+1'
                },
                onProgress: function (progress) {
                  console.log(progress)
                },
                onSuccess: (message) => {
                  this.otherTypesMessagePanelVisible = false;
                  this.sendMessage(message);
                },
                onFailed: (e) => {
                  console.log('error :', e);
                }
              });
            })
          }
        });
      },
      sendOrderMessage(order) {
        //GoEasyIM自定义消息,实现订单发送
        GoEasy.im.createCustomMessage({
          type: 'order',
          payload: order,
          to: this.to,
          notification: {
            title: this.currentUser.name + '发来一个订单',
            body: '[订单消息]',
            sound: 'message',
            badge: '+1'
          },
          onSuccess: (message) => {
            this.otherTypesMessagePanelVisible = false;
            this.sendMessage(message);
          },
          onFailed: (e) => {
            console.log('error :', e);
          }
        });
        this.orderList.visible = false;
      },
      showActionPopup(message) {
        const MAX_RECALLABLE_TIME = 3 * 60 * 1000; //3分钟以内的消息才可以撤回
        this.messageSelector.messages = [message];
        if ((Date.now() - message.timestamp) < MAX_RECALLABLE_TIME && message.senderId === this.currentUser.id && message.status === 'success') {
          this.actionPopup.recallable = true;
        } else {
          this.actionPopup.recallable = false;
        }
        this.actionPopup.visible = true;
      },
      hideActionPopup () {
        this.actionPopup.visible = false;
        this.actionPopup.message = null;
      },
      deleteSingleMessage() {
        uni.showModal({
          content: '确认删除？',
          success: (res) => {
            this.actionPopup.visible = false;
            if (res.confirm) {
              this.deleteMessage();
            }
          },
        })
      },
      deleteMultipleMessages() {
        if (this.messageSelector.messages.length > 0) {
          uni.showModal({
            content: '确认删除？',
            success: (res) => {
              this.messageSelector.visible = false;
              if (res.confirm) {
                this.deleteMessage();
              }
            },
          })
        }
      },
      deleteMessage() {
        GoEasy.im.deleteMessage({
          messages: this.messageSelector.messages,
          onSuccess: (result) => {
            this.messageSelector.messages.forEach(message => {
              let index = this.history.messages.indexOf(message);
              if (index > -1) {
                this.history.messages.splice(index, 1);
              }
            });
            this.messageSelector.messages = [];
          },
          onFailed: (error) => {
            console.log('error:', error);
          }
        });
      },
      recallMessage() {
        this.actionPopup.visible = false;
        GoEasy.im.recallMessage({
          messages: this.messageSelector.messages,
          onSuccess: () => {
            console.log('撤回成功');
          },
          onFailed: (error) => {
            console.log('撤回失败,error:', error);
          }
        });
      },
      editRecalledMessage(text) {
        if (this.audio.visible) {
          this.audio.visible = false;
        }
        this.text = text;
      },
      showCheckBox() {
        this.messageSelector.messages = [];
        this.messageSelector.visible = true;
        this.actionPopup.visible = false;
      },
      selectMessages(e) {
        const selectedMessageIds = e.detail.value;
        let selectedMessages = [];
        this.history.messages.forEach(message => {
          if (selectedMessageIds.includes(message.messageId)) {
            selectedMessages.push(message);
          }
        })
        this.messageSelector.messages = selectedMessages;
      },
      loadHistoryMessage(scrollToBottom) {//历史消息
        this.history.loading = true;
        let lastMessageTimeStamp = null;
        let lastMessage = this.history.messages[0];
        if (lastMessage) {
          lastMessageTimeStamp = lastMessage.timestamp;
        }
        GoEasy.im.history({
          id: this.group.id,
          type: GoEasy.IM_SCENE.GROUP,
          lastTimestamp: lastMessageTimeStamp,
          limit: 10,
          onSuccess: (result) => {
            uni.stopPullDownRefresh();
            this.history.loading = false;
            let messages = result.content;
            if (messages.length === 0) {
              this.history.allLoaded = true;
            } else {
              if (lastMessageTimeStamp) {
                this.history.messages = messages.concat(this.history.messages);
              } else {
                this.history.messages = messages;
              }
              if (messages.length < 10) {
                this.history.allLoaded = true;
              }
              if (scrollToBottom) {
                this.scrollToBottom();
                //收到的消息设置为已读
                this.markGroupMessageAsRead();
              }
            }
          },
          onFailed: (error) => {
            //获取失败
            console.log('获取历史消息失败:', error);
            uni.stopPullDownRefresh();
            this.history.loading = false;
          }
        });
      },
      showMembers() {//显示群成员
        uni.navigateTo({
          url: './member?members=' + JSON.stringify(this.groupMembers)
        });
      },
      onRecordStart() {
        recorderManager.start();
      },
      onRecordEnd() {
        recorderManager.stop();
      },
      showImageFullScreen(e) {
        let imagesUrl = [e.currentTarget.dataset.url];
        uni.previewImage({
          urls: imagesUrl
        });
      },
      //语音录制按钮和键盘输入的切换
      switchAudioKeyboard() {
        if (!this.audio.visible) {
          recorderManager.authorize().then(() => {
            console.log('录音权限获取成功');
            this.audio.visible = true;
          }).catch((err) => {
            console.log('err:', err)
            uni.showModal({
              title: '获取录音权限失败',
              content: '请先打开麦克风权限'
            });
          });
        } else {
          this.audio.visible = false;
        }
      },
      playVideo(e) {
        this.videoPlayer.visible = true;
        this.videoPlayer.url = e.currentTarget.dataset.url;
        this.$nextTick(() => {
          this.videoPlayer.context.requestFullScreen({
            direction: 0
          });
          this.videoPlayer.context.play();
        });
      },
      playAudio (audioMessage) {
        let playingMessage = this.audioPlayer.playingMessage;

        if (playingMessage) {
          this.audioPlayer.innerAudioContext.stop();
          // 如果点击的消息正在播放，就认为是停止播放操作
          if (playingMessage === audioMessage) {
            return;
          }
        }
        this.audioPlayer.playingMessage = audioMessage;
        this.audioPlayer.innerAudioContext.src = audioMessage.payload.url;
        this.audioPlayer.innerAudioContext.play();
      },
      onVideoFullScreenChange(e) {
        //当退出全屏播放时，隐藏播放器
        if (this.videoPlayer.visible && !e.detail.fullScreen) {
          this.videoPlayer.visible = false;
          this.videoPlayer.context.stop();
        }
      },
      messageInputFocusin() {
        this.otherTypesMessagePanelVisible = false;
        this.emoji.visible = false;
      },
      switchEmojiKeyboard() {
        this.emoji.visible = !this.emoji.visible;
        this.otherTypesMessagePanelVisible = false;
      },
      showOtherTypesMessagePanel() {
        this.otherTypesMessagePanelVisible = !this.otherTypesMessagePanelVisible;
        this.emoji.visible = false;
      },
      chooseEmoji(emojiKey) {
        this.text += emojiKey;
      },
      showOrderMessageList() {
        this.orderList.orders = restApi.getOrderList();
        this.orderList.visible = true;
      },
      hideOrderMessageList() {
        this.orderList.visible = false;
      },
      groupCall() {
        uni.showActionSheet({
          itemList: ['视频通话', '语音通话'],
          success: (res) => {
            const mediaType = res.tapIndex === 0 ? 1 : 0;
            uni.navigateTo({
              url: `./rtc/group/chooseCallee?mediaType=${mediaType}&groupId=${this.group.id}`,
            })
          },
          fail: (res) => {
            console.log(res.errMsg);
          }
        });
      },
      scrollToBottom() {
        this.$nextTick(() => {
          uni.pageScrollTo({
            scrollTop: 2000000,
            duration: 0
          });
        });
      },
      markGroupMessageAsRead() {
        GoEasy.im.markMessageAsRead({
          id: this.to.id,
          type: this.to.type,
          onSuccess: function () {
            console.log('标记群聊已读成功');
          },
          onFailed: function (error) {
            console.log('标记群聊已读失败:', error);
          }
        })
      }
    }
  }
</script>

<style>
@import url('@/static/style/chatInterface.css');
</style>
